package com.hmdp.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.Duration;

/**
 * `RedisConfig` 类是一个 Spring 配置类，负责设置和配置 Redis 相关的 Bean，
 * 以便在 Spring 应用程序中使用。它提供了一个 `RedisTemplate` Bean 用于与 Redis 交互，
 * 以及一个 `RedisCacheManager` Bean 用于管理基于 Redis 的缓存，并设置默认的过期时间。
 *
 * <p>该类使用 `@Configuration` 注解，表明它包含 Spring Bean 的定义和配置方法。
 * 它还使用 `@Slf4j` 注解用于日志记录。</p>
 *
 * <h3>RedisTemplate 配置</h3>
 * <p>`redisTemplate` 方法配置并返回一个 `RedisTemplate` Bean，这是与 Redis 交互的核心类。
 * 应用了以下配置：</p>
 * <ul>
 *   <li>设置 `RedisConnectionFactory` 以建立与 Redis 服务器的连接。</li>
 *   <li>键和值的序列化配置为使用 `StringRedisSerializer` 和 UTF-8 编码，确保键和值以字符串形式存储在 Redis 中。</li>
 *   <li>哈希键和哈希值的序列化也配置为使用 `StringRedisSerializer`。</li>
 * </ul>
 *
 * <h3>RedisCacheManager 配置</h3>
 * <p>`cacheManager` 方法配置并返回一个 `RedisCacheManager` Bean，用于管理基于 Redis 的缓存。
 * 应用了以下配置：</p>
 * <ul>
 *   <li>使用 `RedisCacheConfiguration` 将默认缓存过期时间设置为 10 天。</li>
 *   <li>`RedisCacheManager` 使用提供的 `RedisTemplate` 中的 `RedisConnectionFactory` 构建。</li>
 * </ul>
 *
 * <h3>使用场景</h3>
 * <p>该类通常用于 Spring 应用程序中，以启用基于 Redis 的缓存和数据存储。
 * 配置的 `RedisTemplate` 和 `RedisCacheManager` Bean 可以自动注入到其他组件中以与 Redis 交互。</p>
 *
 * <p>在 Spring 应用程序中的示例用法：</p>
 * <pre>
 * {@code
 * @Autowired
 * private RedisTemplate<String, String> redisTemplate;
 *
 * @Autowired
 * private RedisCacheManager cacheManager;
 * }
 * </pre>
 *
 * <h3>依赖项</h3>
 * <p>该类需要以下依赖项：</p>
 * <ul>
 *   <li>Spring Framework（用于 `@Configuration`、`@Bean` 和 Redis 支持）</li>
 *   <li>Lombok（用于 `@Slf4j` 日志记录）</li>
 *   <li>Redis 客户端库（例如 Lettuce 或 Jedis）</li>
 * </ul>
 *
 * <h3>序列化</h3>
 * <p>所有键和值都使用 `StringRedisSerializer` 进行序列化，确保数据以字符串形式存储在 Redis 中。
 * 这适用于键和值主要是字符串的应用程序。</p>
 *
 * <h3>缓存过期</h3>
 * <p>默认缓存过期时间设置为 10 天。可以通过修改 `RedisCacheConfiguration` 对象中的 `entryTtl` 配置来自定义。</p>
 */
@Configuration
@Slf4j
public class RedisConfig {

    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        log.info("Creating RedisTemplate bean");
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //设置key的序列化方式
        redisTemplate.setKeySerializer(new StringRedisSerializer(StandardCharsets.UTF_8));
        //设置value的序列化方式
        redisTemplate.setValueSerializer(new StringRedisSerializer(StandardCharsets.UTF_8));
        //设置hash的key的序列化方式
        redisTemplate.setHashKeySerializer(new StringRedisSerializer(StandardCharsets.UTF_8));
        //设置hash的value的序列化方式
        redisTemplate.setHashValueSerializer(new StringRedisSerializer(StandardCharsets.UTF_8));
        return redisTemplate;
    }

    //redis缓存管理器配置,设置缓存过期时间为10天
    @Bean
    public RedisCacheManager cacheManager(RedisTemplate<Object, Object> redisTemplate) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofDays(10)); // 设置缓存的默认过期时间为10天

        return RedisCacheManager.builder(redisTemplate.getConnectionFactory())
                .cacheDefaults(config)
                .build();
    }

}
